package com.jsu.clubmanagementsystem.utils;

import io.minio.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.FileChannel;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * MinIO工具类
 */
@Slf4j
@Component
public class MinIOUtil {
    private static MinioClient minioClient;

    @Autowired
    public void setMinioClient(MinioClient minioClient) {
        MinIOUtil.minioClient = minioClient;
    }


    /**
     * 根据日期生成文件名
     *
     * @return
     */
    public static String makeFileName(String fileName) {
        return getDataFormat() + "/" + fileName;
    }

    /**
     * 动态获取日期格式
     *
     * @return
     */
    public static String getDataFormat() {
        return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
    }

    /**
     * 创建存储桶
     *
     * @param bucketName
     * @throws Exception
     */
    public static void createBucket(String bucketName) throws Exception {
        minioClient.makeBucket(MakeBucketArgs.builder()
                .bucket(bucketName)
                .build());
    }

    /**
     * 判断存储桶是否存在
     *
     * @param bucketName
     * @return
     * @throws Exception
     */
    public static boolean existsBucket(String bucketName) throws Exception {
        return minioClient.bucketExists(BucketExistsArgs.builder()
                .bucket(bucketName)
                .build());
    }

    /**
     * 列出所有存储桶
     *
     * @return
     * @throws Exception
     */
    public static List<String> listBucket() throws Exception {
        List<String> buckets = new ArrayList<>();
        minioClient.listBuckets(ListBucketsArgs.builder().build()).stream().map(bucket ->
                buckets.add(bucket.name()));
        return buckets;
    }

    /**
     * 删除存储桶
     * @param bucketName
     * @throws Exception
     */
    public static void deleteBucket(String bucketName) throws Exception{
        minioClient.removeBucket(RemoveBucketArgs.builder()
                .bucket(bucketName)
                .build());
    }

    /**
     * 上传文件（根据直接传入的文件)
     * @param bucketName
     * @param file
     * @throws Exception
     */
    public static String uploadFile(String bucketName, MultipartFile file) throws Exception{
        String fileName=file.getOriginalFilename();
        minioClient.putObject(PutObjectArgs.builder()
                .bucket(bucketName)
                .object(MinIOUtil.getDataFormat()+"/"+fileName)
                .stream(file.getInputStream(),file.getSize(),-1)
                .build());
        return "http://116.62.7.209:9000/club/"+MinIOUtil.getDataFormat()+"/"+fileName;
    }

    /**
     * 上传文件(根据输入流)
     * @param bucketName
     * @param file
     * @param fileName
     * @return
     * @throws Exception
     */
    public static String uploadFile(String bucketName, InputStream file, String fileName) throws Exception{
        minioClient.putObject(PutObjectArgs.builder()
                .bucket(bucketName)
                .object(MinIOUtil.getDataFormat()+"/"+fileName)
                .stream(file,getInputSize(file),-1)
                .build());
        return MinIOUtil.getDataFormat()+"/"+fileName;
    }

    /**
     * 获取输入流大小
     * @param fileStream
     * @return
     * @throws IOException
     */
    private static Long getInputSize(InputStream fileStream) throws IOException {
        // 如果是文件流则直接获取大小
        if (fileStream instanceof FileInputStream) {
            FileChannel channel = ((FileInputStream) fileStream).getChannel();
            return channel.size();
        }

        // 判断是否为可重复读取的缓冲流方案
        if (!fileStream.markSupported()) {
            //否，强转成缓冲流
            fileStream = new BufferedInputStream(fileStream);
        }
        fileStream.mark(Integer.MAX_VALUE);
        long size = 0;
        //一次读取最大的字节数
        byte[] buffer = new byte[8192];
        int bytesRead;
        //分块读取文件大小
        while ((bytesRead = fileStream.read(buffer)) != -1) {
            size += bytesRead;
        }
        // 重置流位置
        fileStream.reset();
        return size;
    }

    /**
     * 判断文件是否存在
     * @param bucketName
     * @param objectName
     * @return
     */
    public static boolean existsFile(String bucketName,String objectName){
        try {
            StatObjectResponse statObjectResponse = minioClient.statObject(StatObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .build());
        }catch(Exception e){
            log.error(e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * 获取文件url
     * @param bucketName
     * @param objectName
     * @return
     */
    public static String getFileUrl(String bucketName,String objectName){
        String url="";
        if(existsFile(bucketName,objectName)){
            try {
                url=minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .method(Method.GET)
                        .build());
                return url;
            }catch(Exception e){
                log.error(e.getMessage());
                return "";
            }
        }
        return "";
    }
}